package com.khstudio.videocapture.view;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.SurfaceTexture;
import android.media.MediaFormat;
import android.util.AttributeSet;
import android.view.Surface;
import android.view.TextureView;

import com.khstudio.api.util.KhLog;
import com.khstudio.videocapture.decoder.KhMediaDecoder;
import com.khstudio.videocapture.decoder.KhMediaDecoder.OnMediaDecoderErrorListener;
import com.khstudio.videocapture.decoder.KhMediaDecoder.OnMediaDecoderGetFrameListener;
import com.khstudio.videocapture.decoder.KhMediaDecoder.OnMediaDecoderPlayListener;
import com.khstudio.videocapture.decoder.KhMediaDecoder.OnMediaDecoderPrepareListener;
import com.khstudio.videocapture.decoder.KhMediaDecoder.OnMediaDecoderReleaseListener;
import com.khstudio.videocapture.decoder.KhMediaDecoder.OnMediaDecoderSeekListener;

public class VideoPlayerView_Kh extends TextureView implements TextureView.SurfaceTextureListener {
    private KhMediaDecoder  mMediaDecoder;

    private Surface mSurface;

    private int mVideoWidth;
    private int mVideoHeight;

    public VideoPlayerView_Kh(Context context) {
        this(context, null);
    }

    public VideoPlayerView_Kh(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public VideoPlayerView_Kh(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        KhLog.v("KhVideoPlayerView attrs = %s , defStyle = %d",(attrs==null ? null: attrs.toString()),defStyle);

        _init();

        this.setSurfaceTextureListener(this);
    }

    public interface OnVideoPlayerPrepareListener {
        void onPrepare();
    }

    public interface OnVideoPlayerPlayListener {
        void onPlay(boolean eos);
    }

    public interface OnVideoPlayerSeekListener {
        void onSeek();
    }

    public interface OnVideoPlayerGetFrameListener {
        void onGetFrame(Bitmap frame, boolean isLast);
    }

    public interface OnVideoPlayerErrorListener {
        void onError(int what, int extra);
    }

    public interface OnVideoPlayerReleaseListener {
        void onRelease();
    }

    public void setOnVideoPlayerSeekListener(final OnVideoPlayerSeekListener l) {
        mMediaDecoder.setOnSeekListener(new OnMediaDecoderSeekListener() {
            @Override
            public void onSeek(KhMediaDecoder md) {
                if(l != null) l.onSeek();
            }
        });
    }

    public void setOnVideoPlayerPlayListener(final OnVideoPlayerPlayListener l) {
        mMediaDecoder.setOnPlayListener(new OnMediaDecoderPlayListener() {
            @Override
            public void onPlay(KhMediaDecoder md, boolean eos) {
                if(l != null) l.onPlay(eos);
            }
        });
    }

    public void setOnVideoPlayerGetFrameListener(final OnVideoPlayerGetFrameListener l) {
        mMediaDecoder.setOnGetFrameListener(new OnMediaDecoderGetFrameListener() {
            @Override
            public void onGetFrame(KhMediaDecoder md, Bitmap frame, boolean isLast) {
                if(l != null) l.onGetFrame(frame, isLast);
            }
        });
    }

    public void setOnVideoPlayerErrorListener(final OnVideoPlayerErrorListener l) {
        mMediaDecoder.setOnErrorListener(new OnMediaDecoderErrorListener() {
            @Override
            public void onError(KhMediaDecoder md, int what, int extra) {
                if(l != null) l.onError(what, extra);
            }
        });
    }

    public void setOnVideoPlayerReleaseListener(final OnVideoPlayerReleaseListener l) {
        mMediaDecoder.setOnReleaseListener(new OnMediaDecoderReleaseListener() {
            @Override
            public void onRelease(KhMediaDecoder md) {
                if(l != null) l.onRelease();
            }
        });
    }

    @Override
    public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
        KhLog.v("KhVideoPlayerView : onSurfaceTextureAvailable width = %d , height = %d",width, height);
        if(mSurface == null) {
            mSurface = new Surface(surface);
        } else {
            mSurface.release();
            mSurface = new Surface(surface);
        }

        mMediaDecoder.setSurface(mSurface);
    }

    @Override
    public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
        KhLog.v("KhVideoPlayerView : onSurfaceTextureSizeChanged width = %d , height = %d",width, height);
    }

    @Override
    public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
        KhLog.v("KhVideoPlayerView : onSurfaceTextureDestroyed");
        mMediaDecoder.release();

        mSurface.release();
        mSurface = null;
        return false;
    }

    @Override
    public void onSurfaceTextureUpdated(SurfaceTexture surface) {
        KhLog.v("KhVideoPlayerView : onSurfaceTextureUpdated");
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int oWidthSize  = MeasureSpec.getSize(widthMeasureSpec);
        int oWidthMode  = MeasureSpec.getMode(widthMeasureSpec);
        int oHeightSize = MeasureSpec.getSize(heightMeasureSpec);
        int oHeightMode = MeasureSpec.getMode(heightMeasureSpec);
        KhLog.i("KhVideoPlayerView : onMeasure : oWidth = %d oHeight = %d",oWidthSize, oHeightSize);

        float oRotation = getRotation();
        if(oRotation == 90 || oRotation == 270) {
            int changeTmp = oWidthSize;
            oWidthSize = oHeightSize;
            oHeightSize = changeTmp;
        }

        if(mVideoWidth > 0 && mVideoHeight > 0) {
            if (mVideoWidth >= mVideoHeight) {
                oHeightSize = (int) ((double) oWidthSize * (double) mVideoHeight / (double) mVideoWidth);
            } else if (mVideoWidth < mVideoHeight) {
                oWidthSize = (int) ((double) oHeightSize * (double) mVideoWidth / (double) mVideoHeight);
            }
        }
        KhLog.i("KhVideoPlayerView : onMeasure : resize oWidth = %d oHeight = %d",oWidthSize, oHeightSize);

        int cWidthMeasureSpec  = MeasureSpec.makeMeasureSpec(oWidthSize, oWidthMode);
        int cHeightMeasureSpec = MeasureSpec.makeMeasureSpec(oHeightSize, oHeightMode);

        super.onMeasure(cWidthMeasureSpec, cHeightMeasureSpec);
    }

    @Override
    public void setRotation(float rotation) {
        requestLayout();
        super.setRotation(rotation);
    }

    private void _init() {
        mMediaDecoder = new KhMediaDecoder();

        mSurface = null;

        mVideoWidth = 0;
        mVideoHeight = 0;
    }

    public void setDataSource(String src) {
        mMediaDecoder.setDataSource(src);
    }

    public String getDataSource() {
        return mMediaDecoder.getDataSource();
    }

    public void prepare(final OnVideoPlayerPrepareListener l) {
        if(l == null) {
            mMediaDecoder.prepare(null);
        } else {
            mMediaDecoder.prepare(new OnMediaDecoderPrepareListener() {

                @Override
                public void onPrepare(KhMediaDecoder md) {
                    MediaFormat format = md.getVideoFormat();
                    mVideoWidth = format.getInteger(MediaFormat.KEY_WIDTH);
                    mVideoHeight = format.getInteger(MediaFormat.KEY_HEIGHT);
                    KhLog.i("KhVideoPlayerView : prepare : Video width = %d height = %d", mVideoWidth, mVideoHeight);

                    requestLayout();

                    if(l != null) l.onPrepare();
                }
            });
        }
    }

    public void seek(long timeMs) {
        mMediaDecoder.seek(timeMs*1000);
    }

    public boolean isPlay() {
        return mMediaDecoder.isPlay();
    }

    public void play() {
        mMediaDecoder.play();
    }

    public void getFrame(long timeMs) {
        mMediaDecoder.getFrame(timeMs*1000, KhMediaDecoder.SEEK_TO_ACCURACY);
    }

    public void getFrameList(long sTimeMs, long eTimeMs, int tCnt) {
        mMediaDecoder.getFrameList(sTimeMs*1000, eTimeMs*1000, tCnt, true);
    }

    public void stop() {
        mMediaDecoder.stop();
    }

    public void release() {
        mMediaDecoder.release();
    }

    public long getDurationMs() {
        return mMediaDecoder.getDurationUs() / 1000;
    }

    public long getCurrentTimeMs() {
        return (mMediaDecoder != null) ? mMediaDecoder.getCurrnetTimeUs() / 1000 : -1;
    }
}